/** \file Main.cc
 * Definitions for the exception framework.
 *
 * (c) Copyright  Semih Cemiloglu
 * All rights reserved, see COPYRIGHT file for details.
 *
 * $Id: Main.cc 119 2006-06-21 04:57:25Z semihc $
 *
 *
 */


#include "Main.hh"
#include <cstdlib>
#include <iostream>
#include "Ex.hh"
#include "Debug.hh"
#include "NewHandler.hh"
#include "SingletonMgr.hh"

using namespace std;
using namespace TC;


TC_IDENT("$Id$");


//! C++ implementation's unexpected handler
std::unexpected_handler TC::CppImpl_unexpected = 0;

//! C++ implementation's terminate handler
std::terminate_handler TC::CppImpl_terminate = 0;



#if TC_DEFINE_MAIN

// main() is to be defined by the framework 
int main(int argc, char* argv[])
{
  //TODO: Setup debug stream?
  return CatchMain(argc,argv);
}

#else

// User opted to use main(), just define a placeholder
// for the TC_main()
int TC_main(int, int, char*[])
{
  return 0;
}

namespace {
  // Trick to call static initialization routine correctly.
  bool si = (StaticInit(), true);
  //TODO: Setup atexit() for StaticDeinit()
}

#endif /* TC_DEFINE_MAIN */


int TC::CatchMain(int argc, char* argv[])
{
  int ret = 1; // Failure
 
  try {
    // Initialize
    StaticInit();
    {
      /*ERASE
      // Register main execution thread
      SharedPtr<Thread> mt(new Thread);
      mt->setTid(Thread::GetCurrentThreadId());
      ThreadMgr::ThreadRunStarted(mt.get());
      */
      // Run the application
      SetRunState(RS_Running);
      ret = TC::PrimaryMain(argc,argv);
      SetRunState(RS_Stopped);
      // Unregister main execution thread by exiting this scope
    }
    // De-initialize
    StaticDeinit();
  }
  catch(const Ex& e) {
    e.print(cerr);
  }
  catch(const std::exception& e) {
    cerr << e.what() << endl;
  }
  catch(...) {
    //TODO: Use our debug stream?
    cerr << "CatchMain:" << UnknownExStr << endl;
  }

  return ret;
}


int TC::PrimaryMain(int argc, char* argv[])
{
  int ret = 1; // Failure by default
  int restart = 0; // Restart count
  bool running = true;
  const int RestartMax = 5; // Maximum restart allowed


  while (running) {
    try {
      // Run the application
      ret = ::TC_main(restart, argc, argv);
      running = false;
    }
    catch(const Ex& e) {
      e.print(cerr);
      if(++restart >= RestartMax)
        running = false;
    }
    catch(const std::exception& e) {
      cerr << e.what() << endl;
      if(++restart > RestartMax)
        running = false;
    }
    catch(...) {
      cerr << "Unknown exception" << endl;
      running = false;
    }
  } // end while

  cerr << "PrimaryMain: Stopping with exit code " << ret << endl;
  return ret;
}



void TC::Global_unexpected()
{
  //TODO: Do the househeeping, flush streams etc.
  // Allow any unexpected exception to happen
}


void TC::Global_terminate()
{
  //TODO: Do your house-keeping first
  if(CppImpl_terminate)
    (*CppImpl_terminate)();
  else
    abort();
}


/**
 * TC_RunState keeps the state of the program. It is not
 * exposed to any part of the program but this module, thus
 * defined local (static) to this module.
 * Strictly speaking accesses to this object should be serialized
 * but it is only overwritten in the main (starting) thread.
 */
static TC::RunState TC_RunState = RS_NotStarted;

//! Get the state of the program
RunState TC::GetRunState()
{ return TC_RunState; }

//! Set the state of the program
RunState TC::SetRunState(RunState rs)
{ 
  RunState old_rs = TC_RunState;
  TC_RunState = rs;
  return old_rs;
}


// Mimics static initialization
void TC::StaticInit()
{
  static bool firsttime = true;

  if(firsttime) {
    firsttime = false;
    SetRunState(RS_StaticInit);
    // Register de-initialization function first
    atexit(StaticDeinit);
    NewHandler* n = NewHandler::Instance();
    n->installHandler(Global_new_handler);
    // Prepare the global singleton manager
    //ERASE: GlobalSingletonMgr();
  }
}


//! Mimics static de-initialization
void TC::StaticDeinit()
{
  static bool firsttime = true;

  if(firsttime) {
    firsttime = false;
    SetRunState(RS_StaticDeinit);
    //ERASE: GlobalSingletonMgr()->destroyAllSingletons();
    NewHandler::Instance()->uninstallHandler();
    NewHandler::DeleteInstance();
  }
}

